package com.qf.ability.gateway.security;

import com.qf.ability.gateway.security.ignore.AuthIgnoreConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler;

/**
 * Gateway的安全认证配置类
 */
@Configuration
//开启SpringSecurity中的Reactive(响应式编程)的安全过滤的功能 和 @EnableWebSecurity对应
@EnableWebFluxSecurity
//启用请求忽略（无需通过身份认证，直接放行的请求）配置类
@EnableConfigurationProperties(AuthIgnoreConfig.class)
public class GatewaySecurityConfigration {

    /**
     * 注入需要认证忽略的url
     */
    @Autowired
    private AuthIgnoreConfig authIgnoreConfig;

    /**
     * 注入Reactive的身份认证管理器
     */
    @Autowired
    private ReactiveAuthenticationManager reactiveAuthenticationManager;

    /**
     * 认证失败的异常处理器
     */
    @Autowired
    private ServerAuthenticationFailureHandler serverAuthenticationFailureHandler;

    @Bean
    public SecurityWebFilterChain configure(ServerHttpSecurity http){

        //创建一个用于身份认证的过滤器 -- 进行自定义的身份认证过程
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(reactiveAuthenticationManager);
        //指定身份认证过程中的转换器 -- 获取请求令牌，转换成BearerTokenAuthenticationToken对象（代表当前的用户身份）
        authenticationWebFilter.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());
        //设置认证失败后的处理器
        authenticationWebFilter.setAuthenticationFailureHandler(serverAuthenticationFailureHandler);

        http
                .httpBasic().disable()
                .csrf().disable()
                .formLogin().disable()
                //添加自定义的过滤器
                // 参数一：代表过滤器对象
                // 参数二：顺序，当前过滤器在进行身份认证时触发
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .authorizeExchange()
                //配置无需认证的url列表，直接访问
                .pathMatchers(authIgnoreConfig.getUrls()).permitAll()
                //所有的options请求全部放行，不进行任何的认证处理，解决跨域问题
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                //配置剩下的所有请求都必须通过身份认证
                .anyExchange().authenticated();

        //构建基于响应式编程的安全过滤器链
        return http.build();
    }
}
